﻿using System.Windows;
using System.Windows.Controls;
using System.Windows.Media;

namespace Songhay.Mvvm.Views
{
    /// <summary>
    /// <see cref="System.Windows.Controls.Canvas"/> with tiled background.
    /// </summary>
    /// <remarks>
    /// This class is based on “Creating tiled backgrounds in Metro style XAML apps”
    /// by Rob Fonseca-Ensor
    /// [http://www.robfe.com/2012/07/creating-tiled-backgrounds-in-metro-style-xaml-apps/]
    /// </remarks>
    public class TileCanvas : Canvas
    {
        /// <summary>
        /// Initializes a new instance of the <see cref="TileCanvas"/> class.
        /// </summary>
        public TileCanvas()
        {
            this.SizeChanged += (s, args) =>
            {
                this.Tile();
            };
        }

        /// <summary>
        /// <see cref="System.Windows.DependencyProperty"/>
        /// for <see cref="System.Windows.Media.Imaging.BitmapImage"/>.
        /// </summary>
        public static readonly DependencyProperty TileableImageSourceProperty =
            DependencyProperty.Register("TileableImageSource",
                typeof(ImageSource),
                typeof(TileCanvas),
                new PropertyMetadata(TileableImagePropertyChanged));

        /// <summary>
        /// Gets or sets the tileable image.
        /// </summary>
        /// <value>
        /// The tileable image.
        /// </value>
        public ImageSource TileableImageSource
        {
            get { return (ImageSource)this.GetValue(TileableImageSourceProperty); }
            set { this.SetValue(TileableImageSourceProperty, value); }
        }

        /// <summary>
        /// Gets or sets the height of the tileable image source.
        /// </summary>
        /// <value>
        /// The height of the tileable image source.
        /// </value>
        public double TileableImageSourceHeight
        {
            get { return (double)GetValue(TileableImageSourceHeightProperty); }
            set { SetValue(TileableImageSourceHeightProperty, value); }
        }

        // Using a DependencyProperty as the backing store for TileableImageSourceHeight.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty TileableImageSourceHeightProperty =
            DependencyProperty.Register("TileableImageSourceHeight",
                typeof(double), typeof(TileCanvas), new PropertyMetadata(TileableImagePropertyChanged));

        /// <summary>
        /// Gets or sets the width of the tileable image source.
        /// </summary>
        /// <value>
        /// The width of the tileable image source.
        /// </value>
        public double TileableImageSourceWidth
        {
            get { return (double)GetValue(TileableImageSourceWidthProperty); }
            set { SetValue(TileableImageSourceWidthProperty, value); }
        }

        // Using a DependencyProperty as the backing store for TileableImageSourceWidth.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty TileableImageSourceWidthProperty =
            DependencyProperty.Register("TileableImageSourceWidth",
                typeof(double), typeof(TileCanvas), new PropertyMetadata(TileableImagePropertyChanged));

        static void TileableImagePropertyChanged(DependencyObject sender, DependencyPropertyChangedEventArgs args)
        {
            var tileCanvas = sender as TileCanvas;
            if (tileCanvas == null) return;
            tileCanvas.Tile();
        }

        void Tile()
        {
            var size = this.RenderSize;
            if (size == default(Size)) return;

            this.Children.Clear();

            var width = (int)this.TileableImageSourceWidth; if (width < 32) width = 32;
            var height = (int)this.TileableImageSourceHeight; if (height < 32) height = 32;

            for (int x = 0; x < size.Width; x += width)
            {
                for (int y = 0; y < size.Height; y += height)
                {
                    var i = new Image
                    {
                        Height = this.TileableImageSourceHeight,
                        Source = this.TileableImageSource,
                        Width = this.TileableImageSourceWidth
                    };
                    Canvas.SetLeft(i, x);
                    Canvas.SetTop(i, y);
                    this.Children.Add(i);
                }
            }

            this.Clip = new RectangleGeometry { Rect = new Rect { Height = size.Height, Width = size.Width } };
        }
    }
}
